<?php

defined('__MAPEXEC__') or die('No direct access allowed');

/**
 * Exports a map as a Yahoo! map.
 */
class Maps_Export_Yahoo extends Maps_Export_HTML {
  
  /**
   * Class constructor
   * @param   string  Optional Yahoo! maps API key
   * @return  void
   */
  public function __construct($apiKey='') {
    parent::__construct($apiKey);
    $this->setAPIURL('http://api.maps.yahoo.com/ajaxymap?v=%s&appid=%s');
    $this->setAPIVersion('3.8');
    $this->apiKeyRequired = true;
  }
  
  /**
   * Gets the map layer control type.
   * @param   string  The map layer control type
   * @return  string  Yahoo! Maps type
   */
  protected function getLayerControlType($type='default') {
    $controlType = '';
  	switch ($type)
    {
  		case 'hybrid':
        $controlType = 'YAHOO_MAP_HYB';
        break;
      case 'satellite':
        $controlType = 'YAHOO_MAP_SAT';
        break;
      default:
        $controlType = 'YAHOO_MAP_REG';
        break;
  	}
    return $controlType;
  }
  
  /**
   * Gets the Yahoo! maps navigation code.
   * @param   string  Type of map navigation
   * @return  string  Yahoo! Maps navigation code
   */
  protected function getNavigationType($type='default') {
    $navType = '';
  	switch ($type)
    {
      case 'large';
        $navType = $this->getNavigationType('zoom_long') . ' ' . $this->getNavigationType('pan');
        break;
      case 'small';
        $navType = $this->getNavigationType('zoom_short') . ' ' . $this->getNavigationType('pan');
        break;
      case 'zoom_long':
        $navType = 'map.addZoomLong();';
        break;
      case 'zoom_short':
        $navType = 'map.addZoomShort();';
        break;
      case 'pan':
        $navType = 'map.addPanControl();';
        break;
    }
    return $navType;
  }
  
  /**
   * Render the JavaScript API version
   * @param   void
   * @return  mixed   JavaScript API version
   */
  protected function renderAPIVersion() {
    return $this->apiVersion;
  }
  
  /**
   * Renders the HTML and JavaScript code for Point Of Interest icons
   * @param   Maps_Icon_Manager_Common   Icon manager object
   * @return  string              HTML and JavaScript code
   */
  protected function renderIconCode(Maps_Icon_Manager_Common $iconManager) {
    $output = '';
    
    if ( $iconManager->hasItems() ) {
      $output .=  $this->writeLn('Maps.Icons.Manager.Factory.create("yahoo", function() {') .
                    $this->indentLn('var icon;') .
                    $this->writeLn();
      
      while ($icon = $iconManager->next()) {
        $output .=  $this->writeLn('icon = new YImage("'.$icon->getIconImageURL().'", ' .
                    'new YSize('.$icon->getIconWidth().','.$icon->getIconHeight().'), ' .
                    'new YCoordPoint('.$icon->getInfoWindowOffsetX().','.$icon->getInfoWindowOffsetY().'), ' .
                    'new YCoordPoint('.$icon->getAnchorOffsetX().','.$icon->getAnchorOffsetY().'));') .
                    $this->writeLn('this.add("'.$icon->getId().'", icon);') .
                    $this->writeLn();
      }
      
      $output .=  $this->outdentLn('});');
    }
    
    return $output;
  }
  
  /**
   * Renders the info window overlay HTML and JavaScript code
   * @param   Maps_Map_Common   Map object
   * @return  String            JavaScript code to add info windows to the map
   */
  private function renderInfoWindowOpen(Maps_Map_Common $map) {
    $str = '';
    if ( $map->directionsEnabled() ) {
      $str .= $this->writeLn('var infoWindowOpen = function(i) {') .
                $this->indentLn('var mapManager = Maps.Manager.Factory.get("yahoo");') .
                //$this->writeLn('var html = mapManager.createDirectionsToForm("'.$map->getId().'", "'.$map->lang->get('dir_form_head_to').'", "'.$map->lang->get('dir_form_label_start').'", "'.$map->lang->get('dir_form_button').'", poiLocs[i]) +') .
                //  $this->indentLn('mapManager.createDirectionsFromForm("'.$map->getId().'", "'.$map->lang->get('dir_form_head_from').'", "'.$map->lang->get('dir_form_label_end').'", "'.$map->lang->get('dir_form_button').'", poiLocs[i])') .
                //$this->outdentLn('var tabs = [') .
                //  $this->indentLn('new google.maps.InfoWindowTab("'.$map->lang->get('tab_about').'", poiInfo[i]),') .
                //  $this->writeLn('new google.maps.InfoWindowTab("'.$map->lang->get('tab_directions').'", html)') .
                //$this->outdentLn('];') .
                $this->writeLn('pois[i].openSmartWindow(poiInfo[i]);') .
                $this->writeLn('mapManager = null;') .
              $this->outdentLn('};');
    } else {
      $str .= $this->writeLn('var infoWindowOpen = function(i) {') .
                $this->indentLn('pois[i].openSmartWindow(poiInfo[i]);') .
              $this->outdentLn('};');
    }
    
    return $str;
  }
  
  /**
   * Renders the JavaScript code to display a Yahoo map.
   * @param   Maps_Map_Common   The map object to export
   * @return  string            HTML and JavaScript code
   */
  protected function renderInvocationCode(Maps_Map_Common $map) {
    $str =  $this->writeLn( $this->openScript(null, true) ) .
              $this->indentLn('var mapManager = Maps.Manager.Factory.get("yahoo");') .
              $this->writeLn() .
              $this->writeLn('mapManager.add(function() {') .
                $this->indentLn() .
                $this->renderInvocationVariables($map) .
                $this->writeLn() .
                $this->renderMapNavigation( $map->getNavigationControls() ) .
                $this->writeLn() .
                $this->renderMapLayerControls( $map->getLayerControls() ) .
                $this->writeLn() .
                $this->renderMapPolygons($map) .
                $this->writeLn() .
                $this->renderMapLines($map) .
                $this->writeLn() .
                $this->renderMapPOIs($map) .
                $this->writeLn();
    
    if ( $map->optimalZoomEnabled() ) {
      $str .=   $this->writeLn('bds = map.getBestZoomAndCenter(geoCoords);') .
                $this->writeLn('map.drawZoomAndCenter(bds.YGeoPoint, bds.zoomLevel);');
    } else {
      $str .=   $this->writeLn('map.drawZoomAndCenter(latlng, '.$map->getZoomLevel().');');
    }
    
    $str .=     $this->writeLn('return map;') .
              $this->outdentLn('});') .
            $this->outdentLn( $this->closeScript(true) );
    return $str;
  }
  
  /**
   * Renders the JavaScript variable declarations for all variables used
   * in the invocation code.
   * @param   Maps_Map_Common   Map object
   * @return  String            JavaScript variable declarations
   */
  protected function renderInvocationVariables(Maps_Map_Common $map) {
    $str =  $this->writeln('var map = new YMap( document.getElementById("'.$map->getId().'") );') .
            $this->writeLn('var bds = null;') .
            $this->writeLn('var pois = [];') .
            $this->writeLn('var geoCoords = [];') .
            $this->writeLn('var latlng = null;') .
            $this->writeLn('var line = null;') .
            $this->writeLn('var poiInfo = {};') .
            $this->writeLn('var poiLocs = {};') .
            $this->writeLn('var polygon = null;') .
            $this->writeLn('var iconManager = Maps.Icons.Manager.Factory.get("yahoo");') .
            $this->writeLn('var sidebar = document.getElementById("'.$map->getId().'_sidebar");') .
            $this->writeLn('var sidebarLinks = null;') .
            $this->writeLn('var s = 0;') .
            $this->writeLn('var sLen = 0') .
            $this->writeLn() .
            $this->renderInfoWindowOpen($map) .
            $this->writeLn() .
            $this->writeLn('var sidebarClickHandler = function(i) {') .
              $this->indentLn('return function() {') .
                $this->indentLn('infoWindowOpen(i);') .
                $this->writeLn('return false;') .
              $this->outdentLn('};') .
            $this->outdentLn('};') .
            $this->writeLn() .
            $this->writeLn('var poiClickHandler = function(i) {') .
              $this->indentLn('return function() { infoWindowOpen(i); };') .
            $this->outdentLn('};');
    
    return $str;
  }
  
  /**
   * Renders the map layer controls.
   * @param   array   $layerControls Array of layer control types.
   * @return  string  JavaScript for layer controls.
   */
  private function renderMapLayerControls(array $layerControls) {
    $output = '';
    
    if ( !empty($layerControls) ) {
      $output .= $this->write('map.addTypeControl( [');
      foreach ($layerControls as $index => $type) {
        if ($index > 0) {
          $output .= ', ';
        }
        $output .= $this->getLayerControlType($type);
      }
      $output .= '] );';
    }
    
    return $output;
  }
  
  /**
   * Renders the map lines.
   * @param   Maps_Map_Common   Map object
   * @return  String            JavaScript map line code
   */
  private function renderMapLines(Maps_Map_Common $map) {
    $line = null;
    $latlng = null;
    $output = '';
    
    if ($map->lines->getCount() < 1) {
      return $output;
    }
    
    while ($line = $map->lines->next()) {
      $output .= $this->write('line = new YPolyline([');
      if ($line->getCount() > 1) {
        while ($latlng = $line->next()) {
          if ($line->getPointer() > 1) {
            $output .= ', ';
          }
          $output .= 'new YGeoPoint('.$latlng.')';
        }
        $output .=  '], "'.$line->getStrokeColor().'", '.$line->getStrokeWeight().', '.$line->getStrokeOpacity().');' .
                    $this->writeLn() .
                    $this->writeLn('map.addOverlay(line);');
      }
    }
    
    return $output;
  }
  
  /**
   * Renders the map navigational elements.
   * @param   array   $navControls List of map navigation control types.
   * @return  string  JavaScript for map navigation controls.
   */
  private function renderMapNavigation(array $navControls) {
    $controlType = '';
    $output = '';

    if (empty($navControls)) {
      return $output;
    }

    foreach ($navControls as $control) {
      $output .= $this->writeLn( $this->getNavigationType($control) );
    }

    return $output;
  }
  
  /**
   * Renders the code for map Points Of Interest (markers).
   * @param   Maps_Map_Common   Map object
   * @return  String            JavaScript code to add map Points of Interest
   */
  private function renderMapPOIs(Maps_Map_Common $map) {
    $index = 0;
    $output = '';
    $poi = null;
    $title = '';
    $info = '';
    $lat = null;
    $lng = null;
    $mapId = $map->getId();
    
    while ($poi = $map->pois->next()) {
      $lat = $poi->getLat();
      $lng = $poi->getLng();
      
      if ( isset($lat) && isset($lng) ) {
        $info = $this->renderPoiInfo($poi, $map);
        $name = $this->escape( $poi->getName() );
        $iconName = $poi->getIconName();
        
        $output .=  $this->writeLn('latlng = new YGeoPoint('.$lat.','.$lng.');') .
                    $this->writeLn('geoCoords.push(latlng);');
        
        if ( empty($iconName) ) {
          $output .= $this->writeLn('pois['.$index.'] = new YMarker(latlng);');
        } else {
          $output .= $this->writeLn('pois['.$index.'] = new YMarker(latlng, iconManager.get("'.$iconName.'") );');
        }
        
        $output .=  $this->writeLn('poiInfo['.$index.'] = "'.$this->escape($info).'";') .
                    $this->writeLn('YEvent.Capture(pois['.$index.'], EventsList.MouseClick, poiClickHandler('.$index.'));') .
                    $this->writeLn('map.addOverlay(pois['.$index.']);') .
                    $this->writeLn();
      }
      
      $index++;
    }
    
    $output .=  $this->writeLn('if (sidebar) {') .
                  $this->indentLn('sidebarLinks = sidebar.getElementsByTagName("a");') .
                  $this->writeLn('s = 0;') .
                  $this->writeLn('sLen = sidebarLinks.length;') .
                  $this->writeLn('while (s < sLen) {') .
                    $this->indentLn('sidebarLinks[s].onclick = sidebarClickHandler(s);') .
                    $this->writeLn('s++;') .
                  $this->outdentLn('}') .
                  $this->writeLn('sidebarLinks = null;') .
                  $this->writeLn('sidebar = null;') .
                $this->outdentLn('}') .
                $this->writeLn() .
                $this->writeLn('iconManager = null;');

    return $output;
  }
  
  /**
   * Renders the map polygon code (not supported by Yahoo! Maps AJAX API)
   * @param   Maps_Map_Common   Map object
   * @return  String            JavaScript code for map polgons
   */
  private function renderMapPolygons(Maps_Map_Common $map) {
    return '';
  }
  
  protected function renderPoiLinks(Maps_Map_POI $poi, Maps_Map_Common $map) {
    $address = '';
    $output = '';
    
    if ( $map->directionsEnabled() && $poi->hasLocation() ) {
      $address = rawurlencode( $poi->location->__toString() );
      $output = '<p class="mapPoiLinks">' .
          '<strong>' . $map->lang->get('dir_link_directions') . '</strong>' .
          '<a href="http://maps.yahoo.com/#ard=1&mvt=m&lat='.$poi->getLat().'&lon='.$poi->getLng().'&zoom=7&q1=' . $address . '" target="_blank">' . $map->lang->get('dir_link_to') . '</a> | ' .
          '<a href="http://maps.yahoo.com/#ard=1&mvt=m&lat='.$poi->getLat().'&lon='.$poi->getLng().'&zoom=7&q2=' . $address . '" target="_blank">' . $map->lang->get('dir_link_from') . '</a>' .
          '</p>';
    }
    
    return $output;
  }
  
}

?>